#ifndef __MCS__VALUE__HPP
#define __MCS__VALUE__HPP

#include "Object.hpp"
#include <ostream>

class Value : public Object
{
protected:
	Value() {}
	virtual ~Value() {}
public:
	enum DataType
	{
		Null, Int, Str, Bool, Real
	};

	static String nameForType(DataType type);
	static DataType typeForName(String const & typeName);

	virtual DataType dataType() const = 0;
	
	String toString() const
	{
		std::stringstream str;
		stream(str);
		return str.str();
	}

	virtual std::ostream & stream(std::ostream & str) const = 0;
};

inline std::ostream & operator<<(std::ostream & stream, Value::DataType type)
{
	return stream << Value::nameForType(type);
}

inline std::ostream & operator<<(std::ostream & stream, Value const & val)
{
	return val.stream(stream);
}

inline std::ostream & operator<<(std::ostream & stream, ptr<Value> val)
{
	return val->stream(stream);
}

class IntValue : public Value
{
public:
	explicit IntValue(int val) : value_(val) {}

	virtual DataType dataType() const { return Int; }

	int value() const { return value_; }
	void setValue(int val) { value_ = val; }

	virtual std::ostream & stream(std::ostream & str) const
	{
		return str << value_;
	}
private:
	int value_;
};

class StrValue : public Value
{
public:
	explicit StrValue(String const & val) : value_(val) {}
	
	virtual DataType dataType() const { return Str; }

	String value() const { return value_; }
	void setValue(String const & val) { value_ = val; }

	virtual std::ostream & stream(std::ostream & str) const
	{
		return str << value_;
	}
private:
	String value_;
};

class BoolValue : public Value
{
public:
	explicit BoolValue(bool val) : value_(val) {}

	virtual DataType dataType() const { return Bool; }

	bool value() const { return value_; }
	void setValue(bool val) { value_ = val; }

	virtual std::ostream & stream(std::ostream & str) const
	{
		return str << (value_ ? "true" : "false");
	}
private:
	bool value_;
};

class RealValue : public Value
{
public:
	explicit RealValue(double val) : value_(val) {}

	virtual DataType dataType() const { return Real; }

	double value() const { return value_; }
	void setValue(double v) { value_ = v; }

	virtual std::ostream & stream(std::ostream & str) const
	{
		return str << value_;
	}
private:
	double value_;
};

#endif //__MCS__VALUE__HPP
